package GA;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.io.InputStreamReader;

import Operations.Operation;
import Operations.CreateObject;
import Operations.ValuesGenerator;
import random.TestClusterBuilder;
import util.*;
import crossover.*;
import mutation.*;
public class ChromosomeFormer {

    public static Chromosome buildNewChromosome(TestClusterBuilder TestCluster) {
    	Map<String, List<CreateObject>> constructors= new LinkedHashMap <String, List<CreateObject>> ();
    	List<Operation> ops = new LinkedList<Operation>();
    	constructors=CreateObject.generateInitialClass(TestCluster);
		for (int i = 0; i < GAConfig.TestCaseSize; i++)
			ops.add(Operation.randomlyGenerate(TestCluster));
		Chromosome chrom = new Chromosome(TestCluster.getCluster(),TestCluster.getRefFactory(),constructors, ops);
		return chrom;
    }
    public static void modifyConstructoParam(Chromosome individual,String cName){
		Map<String, List<CreateObject>> constructorz=individual.getConstructors();
		Map<String, Class<?>> cluster = individual.getCluster();
// get information about predicate
	//	String suggestedField= detectField(BR);
		String suggestedValue= "yup";
		
		String suggestedType= "java.lang.String";
		
		List<CreateObject> listObject=constructorz.get(cName);
		constructorz.clear();
	//	ConstructorDeclared[] cutConst = classToTest.get(cName);
		if (listObject != null) {
			for(CreateObject obj : listObject){
				ConstructorDeclared cut= (ConstructorDeclared) obj.getConstructor().clone();
				Class<?>[] paramsType = cut.getParameterTypes();
				Object[] actualParams = new Object[cut.getParameterTypes().length];
				String[] params = new String[paramsType.length];
				for (int k = 0; k < actualParams.length; k++) {
				if (Filter.isPrimitiveOrStringType(cluster.get(paramsType[k].getName().toString()))){
					String paramType=Filter.PrimitiveGenericConverter(paramsType[k].getName().toString());
					if(paramType.equals(suggestedType))
						if(ValuesGenerator.modifyValue(paramsType[k].getName(),suggestedValue)!=null)
//							if(paramsType[k].getName().equals("java.lang.String")&& suggestedValue.equals("null"))
//								params[k] =null;
//							else
								params[k] =suggestedValue;
						else{
								params[k] =ValuesGenerator.buildValue(paramsType[k].getName());
								suggestedValue=params[k];
						}
				}
//				else
//					params[k] = TestCluster.getReference(paramsType[k].getName(), refFactory);
			}
				cut.setParams(params);
				if (constructorz.get(cName) == null)
					constructorz.put(cName, new LinkedList<CreateObject>());
				List<CreateObject> constr = (List<CreateObject>) constructorz.get(cName);
				constr.add(new CreateObject(cut));
			}
		}
		
	}
    public static void modifyConstructoParamX(Chromosome individual,String cName){

		Map<String, List<CreateObject>> constructorz=individual.getConstructors();
		Map<String, Class<?>> cluster = individual.getCluster();
// get information about predicate
	//	String suggestedField= detectField(BR);
		String suggestedValue= "yupx";
		
		String suggestedType= "java.lang.String";
		
		List<CreateObject> listObject=constructorz.get(cName);
		constructorz.clear();
	//	ConstructorDeclared[] cutConst = classToTest.get(cName);
		if (listObject != null) {
			for(CreateObject obj : listObject){
				ConstructorDeclared cut= (ConstructorDeclared) obj.getConstructor().clone();
				Class<?>[] paramsType = cut.getParameterTypes();
				Object[] actualParams = new Object[cut.getParameterTypes().length];
				String[] params = new String[paramsType.length];
				params=cut.getParams();
				String actuallParam;
				for (int k = 0; k < actualParams.length; k++) {
				if (Filter.isPrimitiveOrStringType(cluster.get(paramsType[k].getName().toString()))){
					String paramType=Filter.PrimitiveGenericConverter(paramsType[k].getName().toString());
					if(paramType.equals(suggestedType)){
						actuallParam=params[k];
						if(params[k]==null)
							actuallParam="null";
						if(!actuallParam.equals(suggestedValue)){
						suggestedValue= ValuesGenerator.modifyValue(paramsType[k].getName(),suggestedValue);
						if(! suggestedType.equals("java.lang.String")&&suggestedValue==null) 
							suggestedValue=params[k];
						else{
					//	if(ValuesGenerator.modifyValue(paramsType[k].getName(),suggestedValue))
								params[k] =ValuesGenerator.modifyValue(paramsType[k].getName(),suggestedValue);
								suggestedValue=params[k];
						}
						}
						else{
							if(ValuesGenerator.getRandomInt(100)<50)
								params[k] =ValuesGenerator.buildValue(paramsType[k].getName());
							}

					}
//					else{
//							if(ValuesGenerator.getRandomInt(100)<50)
//								params[k] =ValuesGenerator.buildValue(paramsType[k].getName());
//								//suggestedValue=params[k];
//						}
				}
			}
				cut.setParams(params);
				if (constructorz.get(cName) == null)
					constructorz.put(cName, new LinkedList<CreateObject>());
				List<CreateObject> constr = (List<CreateObject>) constructorz.get(cName);
				constr.add(new CreateObject(cut));
			}
		}
		
	}

	public static void main(String[] args) {
		try {
	    	 Long randomseed= System.currentTimeMillis();
				ValuesGenerator.reset(randomseed);
				
			Crossover crossoverStrategy = GAOperationsConfig.getCrossoverStrategy();
			Mutation ChangeValueStrategy = GAOperationsConfig.getMutationChangeValueStrategy();
			Mutation MethodInsertStrategy = GAOperationsConfig.getMutationMethodInsertStrategy();
			Mutation MethodDeleteStrategy = GAOperationsConfig.getMutationMethodDeleteStrategy();

			System.out.println("CUT is:" + GAConfig.classFilePath);
			 Set<Class<?>> allClasses = new LinkedHashSet<Class<?>>();
		      //get class from file
		      allClasses.addAll(TestClusterBuilder.readClassFromFile());

		      System.out.println("There are " + allClasses.size() + " classes as input");
		      
		      System.out.println(allClasses);
		      Set<Class<?>> classesToTest = TestClusterBuilder.filterUntestableClasses(allClasses);
		      System.out.println("There are " + classesToTest.size() + " classes to test after filtering");
		      System.out.println(classesToTest);

			// calculate the test cluster and the set of types involved in the
				TestClusterBuilder TestCluster = new TestClusterBuilder(classesToTest);		
			Chromosome chrom1=buildNewChromosome(TestCluster);
			System.out.println(chrom1.toString());
		//execute the chiromosme;

			
			String input;
			BufferedReader in = new BufferedReader(new InputStreamReader(
					System.in));


			while ((input = in.readLine()) != null) {
				//ReflectionExecutor.execute(chrom1);
				int randCohice=2;//ValuesGenerator.getRandomInt(3);
				if (randCohice == 0) {
					System.out.println("Insert Strategy "
							+ MethodInsertStrategy.getClass().getName());
					MethodInsertStrategy.setExtraInfo(TestCluster);
					MethodInsertStrategy.mutateChromosome(chrom1);
					System.out.println("chrom1: " + chrom1);
				}
				else if (randCohice == 1) {
					System.out.println("Input value changed.");
					Chromosome chrom2=chrom1.clone();
					ChangeValueStrategy.mutateChromosome(chrom2);
					System.out.println("chrom1: " + chrom1);
					System.out.println("\n\nchrom2: " + chrom2);
				}
				else if (randCohice == 2){
					System.out.println("Delete Random Method "
							+ MethodDeleteStrategy.getClass().getName());
					MethodDeleteStrategy.setExtraInfo(TestCluster);
					MethodDeleteStrategy.mutateChromosome(chrom1);
					System.out.println("chrom1: " + chrom1);
				
				}
				else if (randCohice == 3){
					System.out.println("Crossover Strategy: "
							+ crossoverStrategy.getClass().getName());
					Chromosome chrom2 = buildNewChromosome(TestCluster);
					System.out.println(chrom2.toString());
					Chromosome[] offspring = crossoverStrategy.crossOver(
							chrom1, chrom2);
					System.out.println("offspring1:" + offspring[0]);
					System.out.println("\noffspring2:" + offspring[1]);
					chrom1= offspring[0].clone();
					System.out.println("\nchrom1:" + chrom1);

				}else  {
					System.out.println("Input value changed.");
					Chromosome chrom2=chrom1.clone();
					modifyConstructoParam(chrom2,"database.DBConnection");
					System.out.println("chrom1: " + chrom1);
					System.out.println("\n\nchrom2: " + chrom2);
				}

					
//				ReflectionExecutor.execute(chrom1);
			}

			System.exit(0);
		} catch (Throwable e) {
			System.err.println("chromFormer.main: " + e);
			System.exit(1);
		}

		}
}
